#include "CWin.h"

#ifdef DKGL_USE_GDI_PLUS
#include <gdiplus.h>
#endif

using namespace CAIG;

CWin::CWin()
{
	mMousePtr = &mDummyMouse;
	hasBkgr   = false;
	hasTimer  = true;
	dwStyle   = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
	mWndPosX  = mWndPosY = CW_USEDEFAULT;
	mWndWidth = mWndHeight = CW_USEDEFAULT;
}

//CWin::CWin(bool useBkgr, bool useTimer)
//{
//	mMousePtr = &mDummyMouse;
//	hasBkgr   = useBkgr;
//	hasTimer  = useTimer;
//	dwStyle   = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
//	mWndPosX  = mWndPosY = CW_USEDEFAULT;
//	mWndWidth = mWndHeight = CW_USEDEFAULT;
//}
//
//CWin::CWin(DWORD style, bool useBkgr, bool useTimer)
//{
//	mMousePtr = &mDummyMouse;
//	hasBkgr   = useBkgr;
//	hasTimer  = useTimer;
//	dwStyle   = style;
//	mWndPosX  = mWndPosY = CW_USEDEFAULT;
//	mWndWidth = mWndHeight = CW_USEDEFAULT;
//}
//
//CWin::CWin(int width, int height, int x, int y, bool useBkgr, bool useTimer)
//{
//	mMousePtr  = &mDummyMouse;
//	hasBkgr    = useBkgr;
//	hasTimer   = useTimer;
//	dwStyle    = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
//	mWndPosX   = x;
//	mWndPosY   = y;
//	mWndWidth  = width;
//	mWndHeight = height;
//}
//
//CWin::CWin(DWORD style, int width, int height, int x, int y, bool useBkgr, bool useTimer)
//{
//	mMousePtr  = &mDummyMouse;
//	hasBkgr    = useBkgr;
//	hasTimer   = useTimer;
//	dwStyle    = style;
//	mWndPosX   = x;
//	mWndPosY   = y;
//	mWndWidth  = width;
//	mWndHeight = height;
//}

bool CWin::init()
{
	HINSTANCE	hInstance = GetModuleHandle(NULL);									// Grab An Instance For Our Window
	WNDCLASS	wndclass;
	HWND		hwnd;

#ifdef DKGL_USE_GDI_PLUS
#pragma comment(lib, "gdiplus.lib")
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR           gdiplusToken;
   
	// Initialize GDI+.
	Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
#endif

#ifdef _UNICODE
	TCHAR		szAppName[] = L"Base";
#else
    char        szAppName[] = "Base";
#endif

	wndclass.style         = CS_HREDRAW | CS_VREDRAW;					// Redraw On Size, And Own DC For Window.
	wndclass.lpfnWndProc   = StaticWndProc;								// WndProc Handles Messages
	wndclass.cbClsExtra    = 0;											// No Extra Window Data
	wndclass.cbWndExtra    = 0;											// No Extra Window Data
	wndclass.hInstance     = hInstance;									// Set The Instance
	wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);			// Load The Default Icon
	wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);				// Load The Arrow Pointer
	if(hasBkgr)
		wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	else
		wndclass.hbrBackground = NULL;									// No Background Required For GL
	wndclass.lpszMenuName  = NULL;										// We Don't Want A Menu
	wndclass.lpszClassName = szAppName;									// Set The Class Name

	if (!RegisterClass(&wndclass))
	{
#ifdef _UNICODE
		MessageBox(NULL, L"Failed to register the window class.", L"ERROR", MB_OK);
#else
        MessageBox(NULL, "Failed to register the window class.", "ERROR", MB_OK);
#endif
		return false;
	}

	hwnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,			// Window Extended Style
						  szAppName,									// Class Name
						  szAppName,									// Window Title
						  dwStyle,										// Window Style
						  mWndPosX, mWndPosY,							// Window Position
						  mWndWidth,									// Window Width
						  mWndHeight,									// Window Height
						  NULL,											// No Parent Window
						  NULL,											// No Menu
						  hInstance,									// Instance
						  this);

	if (!hwnd)
	{
#ifdef _UNICODE
		MessageBox(NULL, L"Window creation error.", L"ERROR" ,MB_OK);
#else
        MessageBox(NULL, "Window creation error.", "ERROR" ,MB_OK);
#endif
		return false;
	}

	ShowWindow (hwnd, SW_SHOW);

	// init KB buf
	for(int i=0;i<256;i++)
		mKeys[i] = false;

	// init high resolution timer
	LARGE_INTEGER ticksPerSecond;
	QueryPerformanceFrequency(&ticksPerSecond);
	mTicksPerSec = static_cast<float>(ticksPerSecond.QuadPart);

	return true;
}

float CWin::getTimeInSec() const
{
	LARGE_INTEGER tick;

	QueryPerformanceCounter(&tick);

	return static_cast<float>(tick.QuadPart)/mTicksPerSec;
}

void CWin::go()
{
	MSG	msg;

	while (true)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (msg.message==WM_QUIT)
			{
				break;
			}
			else
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		}

		update();

		WINDOWPLACEMENT wndpl;
		GetWindowPlacement(hWnd, &wndpl);

		if ((wndpl.showCmd != SW_HIDE) &&
			(wndpl.showCmd != SW_MINIMIZE) &&
			(wndpl.showCmd != SW_SHOWMINIMIZED) &&
			(wndpl.showCmd != SW_SHOWMINNOACTIVE))
		{
			render();
			SwapBuffers (hDC);
		}
		Sleep(1);
	}// Endof while
}

LRESULT CWin::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	POINT	pt;

	switch (msg)
	{
	case WM_CREATE:
		hWnd = hwnd;
		hDC = GetDC (hwnd);
		if(hasTimer)
			SetTimer(hWnd, 0, 33, NULL);
		OnCreate();
		return 0;
	case WM_LBUTTONDOWN:
		mMousePtr->appOnLeftPress(LOWORD (lp), HIWORD (lp));
		mMousePtr->leftPress(LOWORD (lp), HIWORD (lp));
		//LeftDown(LOWORD (lp), mWndHeight - HIWORD (lp));
		return 0;
	case WM_MBUTTONDOWN:
		mMousePtr->appOnMiddlePress(LOWORD (lp), HIWORD (lp));
		mMousePtr->middlePress(LOWORD (lp), HIWORD (lp));
		return 0;
	case WM_RBUTTONDOWN:
		mMousePtr->appOnRightPress(LOWORD (lp), HIWORD (lp));
		mMousePtr->rightPress(LOWORD (lp), HIWORD (lp));
		//RightDown(LOWORD (lp), mWndHeight - HIWORD (lp));
		return 0;
	case WM_LBUTTONUP:
		mMousePtr->appOnLeftRelease(LOWORD (lp), HIWORD (lp));
		mMousePtr->leftRelease(LOWORD (lp), HIWORD (lp));
		//LeftUp (LOWORD (lp), mWndHeight - HIWORD (lp));
		return 0;
	case WM_MBUTTONUP:
		mMousePtr->appOnMiddleRelease(LOWORD (lp), HIWORD (lp));
		mMousePtr->middleRelease(LOWORD (lp), HIWORD (lp));
		return 0;
	case WM_RBUTTONUP:
		mMousePtr->appOnRightRelease(LOWORD (lp), HIWORD (lp));
		mMousePtr->rightRelease(LOWORD (lp), HIWORD (lp));
		//RightUp (LOWORD (lp), mWndHeight - HIWORD (lp));
		return 0;
	case WM_MOUSEMOVE:
		if(!hasTimer)
			mMousePtr->onlyMove(LOWORD(lp), HIWORD(lp));
		return 0;
	case WM_KEYDOWN:
		mKeys[wp] = true;
		KeyDown();
		return 0;
	case WM_KEYUP:
		mKeys[wp] = false;
		KeyUp();
		return 0;
	case WM_TIMER:
		GetCursorPos (&pt);
		ScreenToClient (hWnd, &pt);
		mMousePtr->appOnMove(pt.x, pt.y);
		if(mMousePtr->beLMBDown())
			(mMousePtr->leftDrag)(pt.x, pt.y);
		if(mMousePtr->beMMBDown())
			(mMousePtr->middleDrag)(pt.x, pt.y);
		if(mMousePtr->beRMBDown())
			(mMousePtr->rightDrag)(pt.x, pt.y);
		mMousePtr->onlyMove(pt.x, pt.y);
		//Drag (static_cast<WORD>(pt.x), static_cast<WORD>(mWndHeight - pt.y));
		OnTime();
		InvalidateRect (hWnd, NULL, FALSE);
		return 0;
	case WM_SIZE:
		mWndWidth = LOWORD(lp);
		mWndHeight = HIWORD(lp);
		OnSize(mWndWidth, mWndHeight);
		return 0;
	case WM_PAINT:
		OnPaint();
		if(!hasBkgr)
			SwapBuffers (hDC);
		if(hasTimer)
			ValidateRect (hWnd, NULL);
		else
			InvalidateRect(hWnd, NULL, FALSE);
		return 0;
	case WM_ERASEBKGND:
		// Check To See If Windows Is Trying To Erase The Background
		return 0;
	case WM_DESTROY:
		OnDestroy();
		KillTimer(hWnd, 0);
		PostQuitMessage(0);
		return 0;
	}
}

LRESULT CALLBACK CWin::StaticWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	CWin *win = NULL;

	if(msg == WM_CREATE)
	{
		// retrieve Window instance from window creation data and associate
		win = static_cast<CWin*>(((LPCREATESTRUCT)lp)->lpCreateParams);
		SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<LONG>(win));
	}
	else
		// retrieve associated Window instance
		win = reinterpret_cast<CWin*>(GetWindowLong(hwnd, GWL_USERDATA));

	if (win)
		win->WndProc(hwnd, msg, wp, lp);

	return DefWindowProc(hwnd, msg, wp, lp);
}
